package com.tool4j.util;

import com.tool4j.common.ModelEnum;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.document.Document;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class FileReaderUtil {

    /**
     * 获取附件内容
     *
     * @param filePart
     * @return
     */
    public static Mono<String> getText(FilePart filePart) {
        if (filePart == null) {
            return Mono.just("");
        }
        return isImage(filePart)
                .flatMap(isImage -> {
                    if (Boolean.TRUE.equals(isImage)) {
                        return readImage(filePart);
                    } else {
                        return readFile(filePart);
                    }
                });
    }

    /**
     * 判断是否是图片
     *
     * @param filePart 上传的文件片段
     * @return true 如果是图片，false 否则
     */
    public static Mono<Boolean> isImage(FilePart filePart) {
        // 获取 MIME 类型
        String contentType = filePart.headers().getContentType() != null ?
                filePart.headers().getContentType().toString() : "";
        // 获取文件名并提取扩展名
        String filename = filePart.filename();
        String extension = "";
        if (filename != null && filename.contains(".")) {
            extension = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
        }
        // 常见图片 MIME 类型和扩展名
        Set<String> imageMimeTypes = Set.of(
                "image/jpeg", "image/jpg", "image/png", "image/gif", "image/bmp", "image/webp", "image/tiff"
        );
        Set<String> imageExtensions = Set.of(
                "jpg", "jpeg", "png", "gif", "bmp", "webp", "tiff", "svg"
        );
        // 判断 MIME 类型或扩展名是否匹配
        boolean isByMimeType = imageMimeTypes.contains(contentType.toLowerCase());
        boolean isByExtension = imageExtensions.contains(extension);
        return Mono.just(isByMimeType || isByExtension);
    }

    /**
     * 读取图片内容
     *
     * @param filePart
     * @return
     */
    public static Mono<String> readImage(FilePart filePart) {
        return DataBufferUtils.join(filePart.content()) // 收集所有 DataBuffer 为一个
                .map(dataBuffer -> {
                    byte[] bytes = new byte[dataBuffer.readableByteCount()];
                    dataBuffer.read(bytes); // ✅ 读取数据
                    DataBufferUtils.release(dataBuffer); // 释放内存
                    return bytes;
                })
                // 切换到弹性线程池执行同步阻塞操作（Tika）
                .publishOn(Schedulers.boundedElastic())
                .map(bytes -> {
                    try {
                        Resource resource = new ByteArrayResource(bytes) {
                            @Override
                            public String getFilename() {
                                return filePart.filename();
                            }
                        };

                        OpenAiApi openAiApi = OpenAiApi.builder()
                                .baseUrl(ModelEnum.QWEN_VL_PLUS.getBaseUrl())
                                .apiKey(ModelEnum.QWEN_VL_PLUS.getApiKey())
                                .build();
                        OpenAiChatModel chatModel = OpenAiChatModel.builder().openAiApi(openAiApi).defaultOptions(
                                OpenAiChatOptions.builder().model(ModelEnum.QWEN_VL_PLUS.getModelName()).build()
                        ).build();
                        return ChatClient.create(chatModel).prompt()
                                .user(u -> u.text("解释一下你在这幅图中看到了什么？")
                                        .media(MimeTypeUtils.IMAGE_PNG, resource))
                                .call()
                                .content();
                    } catch (Exception e) {
                        throw new RuntimeException("Tika parsing failed", e);
                    }
                })
                .defaultIfEmpty("")
                .onErrorReturn("");
    }

    /**
     * 读取文件内容
     *
     * @param filePart
     * @return
     */
    public static Mono<String> readFile(FilePart filePart) {
        return DataBufferUtils.join(filePart.content()) // 收集所有 DataBuffer 为一个
                .map(dataBuffer -> {
                    byte[] bytes = new byte[dataBuffer.readableByteCount()];
                    dataBuffer.read(bytes); // ✅ 读取数据
                    DataBufferUtils.release(dataBuffer); // 释放内存
                    return bytes;
                })
                // 切换到弹性线程池执行同步阻塞操作（Tika）
                .publishOn(Schedulers.boundedElastic())
                .map(bytes -> {
                    try {

                        Resource resource = new ByteArrayResource(bytes) {
                            @Override
                            public String getFilename() {
                                return filePart.filename();
                            }
                        };
                        List<Document> documents = new TikaDocumentReader(resource).get();
                        String result = documents.stream()
                                .map(Document::getFormattedContent)
                                .collect(Collectors.joining("\n\n")).trim();
                        if (result.startsWith("source:")) {
                            // 删除第一行（包括换行符）
                            result = result.replaceFirst("^[^\\n]*\\n", "");
                        }
                        return result;
                    } catch (NoSuchMethodError e) {
                        return "暂不支持此文档解析";
                    }
                })
                .defaultIfEmpty("")
                .onErrorReturn("");
    }

    private static String getText(String url) {
        if (StringUtils.hasText(url)) {
            List<Document> documents = new TikaDocumentReader(url).get();
            return documents.stream()
                    .map(Document::getFormattedContent)
                    .collect(Collectors.joining("\n\n"));
        }
        return "";
    }
}
